package com.lks.processor;/*
 * Copyright (C) 2017 Qi Cai Technology Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import com.google.auto.service.AutoService;
import com.lks.annotation.DBClass;
import com.lks.annotation.DBUpdate;
import com.lks.annotation.DateType;
import com.lks.annotation.UpdateType;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.Elements;
import javax.tools.Diagnostic;


import static javax.lang.model.element.Modifier.PUBLIC;

/**
 * TODO this class desription here
 * <p>
 * Created by ww on 2017/7/12.
 */
@AutoService(Processor.class)
public class DBClassProcessor extends AbstractProcessor {
    private static final String PACKAGE_OF_GENERATE_FILE = "me.goldze.mvvmhabit.lks.mylibrary.processor";
    private Messager messager;
    private Filer filer;
    private Elements elements;
    String moduleName = "app";
    Elements elementUtils;
    private String IDBCLASS_ROOT = "me.goldze.mvvmhabit.lks.lksBus.ILksUrlHelper";
    Map<String, String> map = new HashMap<>();
    Map<String, ClassName> classNameMap = new HashMap<>();

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        messager = processingEnvironment.getMessager();
        filer = processingEnvironment.getFiler();
        elements = processingEnv.getElementUtils();
        Map<String, String> options = processingEnv.getOptions();
        elementUtils = processingEnv.getElementUtils();
        if (!options.isEmpty()) {
            moduleName = options.get("moduleName");
        }
    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        if (set.isEmpty()) {
            return false;
        }
        Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(DBClass.class);
        Set<? extends Element> updates = roundEnvironment.getElementsAnnotatedWith(DBUpdate.class);
        messager.printMessage(Diagnostic.Kind.WARNING, "Printing:>>>>>>>DBUpdate " + updates.toString());
        messager.printMessage(Diagnostic.Kind.WARNING, "Printing:>>>>>>>DBUpdate " + elements.toString());
        MethodSpec.Builder builder = MethodSpec.methodBuilder("register")
                .addAnnotation(Override.class)
                .addModifiers(Modifier.PUBLIC);
        for (Element element : elements) {
            DBClass annotation = element.getAnnotation(DBClass.class);

            if (annotation.value()) {
                String tabName = "`" + annotation.tabName() + "`";
                ClassName className = ClassName.get((TypeElement) element);
                map.put(className.reflectionName(), tabName);
                classNameMap.put(className.reflectionName(), className);
                builder.addStatement("me.goldze.mvvmhabit.lks.dbmanager.DBInitUtil.addClass($T.class)", className);
            }
        }
        try {
            for (Element ele : updates) {
                DBUpdate annotation = ele.getAnnotation(DBUpdate.class);
                String fieldName = ele.getSimpleName().toString();
                VariableElement varELe = (VariableElement) ele;
                TypeElement enclosingElement = (TypeElement) varELe
                        .getEnclosingElement();
                String key = enclosingElement.getQualifiedName().toString();
                UpdateType type = annotation.type();
                int version = annotation.version();
                DateType dateType = annotation.dateType();
                String updateString = "";
                if (type == UpdateType.ADD) {
                    updateString = "ALTER TABLE " + map.get(key) + " ADD COLUMN " + fieldName + " " + dateType.toString() + ";";
                }
                builder.addStatement("com.lekusi.lkslib.dbmanager.DBInitUtil.addUpDateHelperBean(" + version + ",\"" + updateString + "\",$T.class)", classNameMap.get(key));

            }
        } catch (Exception e) {

        }


        try

        {
            JavaFile.builder(PACKAGE_OF_GENERATE_FILE,
                    TypeSpec.classBuilder(moduleName + "Db")
                            .addModifiers(PUBLIC)
                            .addSuperinterface(ClassName.get(this.elements.getTypeElement(IDBCLASS_ROOT)))
                            .addMethod(builder.build())
                            .build()
            ).build().writeTo(filer);
        } catch (
                IOException e)

        {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> set = new HashSet<>();
        set.add(DBClass.class.getCanonicalName());
        set.add(DBUpdate.class.getCanonicalName());
        return set;
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }
}
